# 封装解封工具
import random


class MessageTool:
    # 客户机和服务器列表标识
    S = 1
    C = 2
    # 服务器->客户机
    S_LOGIN = 1  # 登录/注册响应
    S_PASSWORD = 2  # 用户密码修改响应
    S_QUEST = 3  # 质询
    S_QUEST_RESULT = 4  # 质询结果
    S_LIST = 5  # 文件列表请求响应
    S_LIST_TRANS = 6  # 文件列表传输
    S_DOWN = 7  # 下载请求响应
    S_DOWN_TRANS = 8  # 下载文件传输
    S_UP = 9  # 上传请求响应
    S_USER_LIST = 10  # 用户信息
    S_OFFLINE = 15  # 离线传输响应

    # 客户机->服务器
    C_LOGIN = 1  # 登录/注册请求
    C_PASSWORD = 2  # 用户密码修改请求
    C_QUEST_RESULT = 3  # 质询结果
    C_LIST = 4  # 文件列表请求
    C_DOWN = 5  # 下载请求
    C_DOWN_ERROR = 6  # 差错回应
    C_UP = 7  # 上传请求
    C_UP_TRANS = 8  # 上传文件传输
    C_OFFLINE = 15  # 离线传输请求
    C_OFFLINE_TRANS = 16  # 离线文件传输

    # 用户间传输
    T_USER_MESSAGE = 11  # 用户消息
    T_USER_FILE_REQ = 12  # 用户间文件传输请求
    T_USER_FILE_RES = 13  # 用户间文件传输响应
    T_USER_FILE_TRANS = 14  # 用户间文件传输

    # 状态标识
    SUCCESS = 1  # 成功
    FAILED = 0  # 失败
    ERROR_CONTROL = 2  # 发送完一轮，请求差控
    MORE_TEAM = 1  # 还有分组
    END = 0  # 传输结束
    ALLOW = 1  # 允许上传/下载
    REFUSE = 0  # 不允许上传/下载
    RIGHT = 1  # 无差错
    WRONG = 0  # 有差错
    PUBLIC = 1  # 公共文件夹
    PRIVATE = 0  # 私人文件夹
    DELETE = 0  # 删除用户
    APPEND = 1  # 添加用户

    class MessageStruct:
        def __init__(self):
            self.function = None  # 功能字
            self.status = None  # 状态字
            self.userNumber = None
            self.fileNumber = None  # 文件编号
            self.message = None  # 内容

    # @staticmethod
    # def mseeagesSplit(msgs):
    #     '''
    #     :function 消息拆分函数
    #     :param msgs: 需要拆分的消息组
    #     :return: 拆分结束的消息对象
    #     '''
    #     while True:
    #         length = int.from_bytes(msgs[:2], byteorder='big', signed=False)
    #         msg = msgs[2:length]
    #         msgs = msgs[length:]
    #         yield MessageTool.unpacking(msg)
    #         if len(msgs) == 0:
    #             break

    @staticmethod
    def packingMs(ms=MessageStruct()):
        return MessageTool.packing(MessageTool.int2bytes(1, ms.function, ms.status, ms.userNumber, ms.fileNumber),
                                   ms.message)

    @staticmethod
    def packing(*args):
        '''
        :function 封装函数将一组bytes组合成一个并添加长度首部
        :param args: 传入需要发送的多个bytes
        :return: 为其添加长度位，并返回组合后的bytes
        '''
        msg = b''
        for bs in args:
            msg += bs
        return MessageTool.int2bytes(2, len(msg)) + msg

    @staticmethod
    def int2bytes(size, *ints):
        '''
        :function 将ints数组编码为bytes
        :param size: 每个整数编码的位数
        :param ints: 需要转化为bytes的整数列表
        :return: 按size将整数数组编码成bytes并返回
        '''
        if size == 1:
            return bytes(ints)
        bs = b''
        for i in ints:
            bs += i.to_bytes(length=size, byteorder='big', signed=False)
        return bs

    @staticmethod
    def bytes2int(size, bs):
        '''
        :function bytes转化回int数组
        :param size: 每个整数的编码位数
        :param bytes: 需要转化的bytes
        :return: 整数数组
        '''
        while True:
            yield int.from_bytes(bs[:size], byteorder='big', signed=False)
            bs = bs[size:]
            if len(bs) == 0:
                break

    @staticmethod
    def unpacking(msg):
        '''
        :function 解封装函数
        :param msg:收到的消息，去掉头部
        :return: 消息结构体
        '''
        ms = MessageTool.MessageStruct()
        ms.function = msg[0]
        ms.status = msg[1]
        ms.userNumber = msg[2]
        ms.fileNumber = msg[3]
        ms.message = msg[4:]
        return ms

    @staticmethod
    def chap(nums, password=12345, length=4):
        '''
        输入一组整数，返回chap认证结果
        :param nums:需要计算的整数数组
        :param password:密码, 默认为12345
        :param length: 求和的结果位数，默认为四个字节
        :return: 计算结果，整数
        '''
        return sum(nums) & (2 ** (length * 8) - 1) ^ password

    @staticmethod
    def getRandomInts(minnum, maxnum):
        '''
        返回一个随机数量的整数数组，大小为2字节或者4字节
        :param minnum: 最少数量
        :param maxnum: 最多数量
        :return: 生成的随机数列表
        '''
        return [random.randint(0, 2 ** (2 * 8) - 1) if random.randint(0, 1) == 0
                else random.randint(2 ** (2 * 8), 2 ** (4 * 8) - 1)
                for i in range(random.randint(minnum, maxnum))]

    @staticmethod
    def locJoin(*args):
        '''
        返回路径
        :param args：传入需要拼接的路径
        :return: 拼接后的地址
        '''
        loc = args[0]
        for i in args[1:]:
            loc = loc + '/' + i
        return loc

    @staticmethod
    def send(sock, data):
        try:
            while data:
                re = sock.send(data)
                data = data[re:]
            return True
        except:
            return False

    @staticmethod
    def recv(sock, headLength):
        try:
            head = b''
            while headLength:
                re = sock.recv(headLength)
                if not re:
                    return None
                headLength -= len(re)
                head += re
            length = int.from_bytes(
                head, byteorder='big', signed=False)  # 先获得长度
            data = b''
            while length:
                if len(data) == 0:
                    return None
                ms = MessageTool.unpacking(data)
                return ms
        except:
            return None
